package main

import (
	"fmt"
	"sync"
	"time"

	"engine/log"
	"gitee.com/ameise84/e3log"
	"gitee.com/ameise84/e3utils/rand"
	"gitee.com/ameise84/e3utils/str_conv"
	"gitee.com/ameise84/e3utils/utils"
	"github.com/fatih/color"
	"github.com/spf13/viper"
	"servers/app/client/conn"
	"servers/app/client/metas"
	"servers/app/client/misc"
	"servers/app/client/protos/game"
	"servers/app/client/protos/game/g101"
	"servers/app/client/protos/relay"
	"servers/internal/net_msg"
	"servers/models/define"
	"servers/models/protos/google/pb/net_protos"
	"servers/models/protos/google/pb/net_protos/games/pb101"
)

var bid = define.BusinessIDType(100001)

type AutoFunc func(conn.Client, int, int)

var autoTestMap = map[define.GameKind]AutoFunc{}

func init() {
	RegisterAutoTest(101, g101.AutoTest)
}

func RegisterAutoTest(gameKind define.GameKind, f AutoFunc) {
	autoTestMap[gameKind] = f
}

func FindAutoTest(gameKind define.GameKind) (f AutoFunc, ok bool) {
	f, ok = autoTestMap[gameKind]
	return
}

func main() {
	defaultPath := utils.GetCurrentExeDir()
	viper.SetConfigType("yaml")
	viper.AddConfigPath(defaultPath)
	viper.SetConfigName("client")
	_ = viper.ReadInConfig()
	viper.SetConfigName("config_base")
	_ = viper.MergeInConfig()

	log.GetLogger().SetLevel(e3log.LevelTrace)
	log.GetLogger().SetFatalExitFunc(func(code int) {}, -1)
	w, err := e3log.NewFileWriter()
	if err != nil {
		log.GetLogger().Error(err.Error()).Println()
	}
	log.GetLogger().AddWriter(w)
	runKind := viper.GetString("run_kind")
	switch runKind {
	case "auto_test":
		runAutoTest()
	case "diy_test":
		runDiyTest()

	}
	log.GetLogger().Wait()
}

func onPush(c conn.Client, msg net_msg.Message) {
}

func runClientTest(hand conn.TaskHandler, ac string, count int) {
	viper.GetStringSlice("addr")
	sleepDur := viper.GetDuration("auto_test.sleep")
	rAddrs := viper.GetStringSlice("addr")
	wg := sync.WaitGroup{}
	wg.Add(count)
	kids := viper.GetStringSlice("game.kind")
	if len(kids) == 0 {
		log.GetLogger().Error("game kind list nil").Println()
	}
	tr := time.NewTicker(5 * time.Second)
	go func() {
	loopTimer:
		for {
			select {
			case _, ok := <-tr.C:
				log.GetLogger().InfoPrintf("run user:%d", conn.CheckUser())
				if !ok {
					break loopTimer
				}
			}
		}
	}()
	for i := 0; i < count; i++ {
		info := metas.AccountInfo{
			Account:    ac + str_conv.ToString(i),
			Bid:        bid,
			GameKindID: str_conv.ToUint32(kids[rand.IntN(len(kids))]),
		}
		opt := conn.Option{
			Task: hand,
			Push: onPush,
			Addr: rAddrs[rand.IntN(len(rAddrs))],
		}
		go conn.Run(&info, &wg, &opt)
		if sleepDur > 0 {
			time.Sleep(sleepDur * time.Millisecond)
		}
	}

	wg.Wait()
	tr.Stop()
	log.GetLogger().Debug("测试完成").Println()
}

func runAutoTest() {
	prefix := viper.GetString("auto_test.prefix")
	count := viper.GetInt("auto_test.count")
	ac := prefix + rand.StringN(8)
	runClientTest(doAutoTest, ac, count)
}

func runDiyTest() {
	ac := viper.GetString("diy_test.account")
	rd := viper.GetBool("diy_test.is_rand")
	if rd {
		ac = ac + rand.StringN(8)
	}
	runClientTest(doDiyTest, ac, 1)
}

func doAutoTest(c conn.Client) {
	kid := c.GetAccountInfo().GameKindID
	relay.Recharge(c, 100000000)

	count := viper.GetInt("game.count")
	sleep := viper.GetInt("game.sleep")
	if count <= 0 {
		count = -1
	}
	if sleep <= 0 {
		sleep = 100
	}
	c.SetServerID(kid)
	if rsp := game.TokenLoginReq(c, &net_protos.GameTokenLoginReq{Token: c.GetGameUrlParams().Token, Ip: "127.0.0.1"}); rsp.Code != 0 {
		return
	}
	if game.SitDownReq(c).ErrCode.Code != 0 {
		return
	}
	// logger.DebugBeanPrintf(c, "SitDownReq")
	if f, ok := FindAutoTest(kid); ok {
		f(c, count, sleep)
	} else {
		log.GetLogger().ErrorPrintf("game kind[%d] auto test func not register", kid)
	}
	// logger.DebugBeanPrintf(c, "StandUpReq")
	game.StandUpReq(c)
}

func doDiyTest(c conn.Client) { // 自定义测试
	relay.Recharge(c, 100000000)
	kid := c.GetAccountInfo().GameKindID
	c.SetServerID(kid)

	if rsp := game.TokenLoginReq(c, &net_protos.GameTokenLoginReq{Token: c.GetGameUrlParams().Token, Ip: "127.0.0.1"}); rsp.Code != 0 {
		return
	}
	if game.SitDownReq(c).ErrCode.Code != 0 {
		return
	}
	rspScene := g101.GameSceneReq(c)
	if misc.IsErrorCode(rspScene.Code) {
		return
	}

	in := ""
loopGame:
	for {
		if rspScene.CurScore < rspScene.Cfg.BetScore[0]*20 {
			relay.Recharge(c, 100000000)
		}
		req := &pb101.GameBetReq{BetKind: pb101.BetKind_Bet, BetIndex: 0, BetScore: rspScene.Cfg.BetScore[0]}
		if rspScene.Scene.FreeTimes > 0 {
			req.BetKind = pb101.BetKind_Free
		}
		rspBet := g101.GameBetReq(c, req)
		if misc.IsErrorCode(rspBet.Code) {
			return
		}

		rspScene.Scene.FreeTimes = rspBet.CurFree.After
		rspScene.Scene.MulIconVal = rspBet.MulIcon.After
		for {
			fmt.Print(color.CyanString("是否继续(y/n):"))
			if _, err := fmt.Scan(&in); err != nil {
				color.Red("输入错误,请重新输入")
				continue
			}

			if in == "y" {
				break
			} else if in == "n" {
				break loopGame
			} else {
				color.Red("输入错误,请重新输入")
			}
		}

		time.Sleep(100 * time.Millisecond)
	}
	game.StandUpReq(c)
}
